home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Atari Compendium
/
The Atari Compendium (Toad Computers) (1994).iso
/
files
/
umich
/
demos
/
gray.lzh
/
FLOYD7.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-05-14
|
8KB
|
375 lines
/* THIS PROGRAM IS WRITTEN BY KLAUS PEDERSEN - micro@imada.ou.dk *\
|* The program NEEDS a ST with High rez monitor, and serverves as*|
\* demostration ONLY.____________________________________________*/
#include <tos.h>
#include <stdlib.h>
#include <portab.h>
#define ERRWIDTH 1024
#define PLANES 3
#define WORDLINE 40 /* words/line */
#define FIXEDNUM 4 /* size of the fixed point numbers */
typedef WORD ERRTYP; /* if FIXEDNUM>4 then ERRTYP must be LONG */
#define MAXGRAY (( (ERRTYP)256 << FIXEDNUM ) - 1)
static ERRTYP Levels[4] = {0, MAXGRAY/3, 2*MAXGRAY/3, MAXGRAY};
WORD Beta, Width, Height, MaxRandom, Flicker, Zoom, n_levels;
ERRTYP Error1Array[ERRWIDTH], Error2Array[ERRWIDTH], *Error1, *Error2;
UWORD Screens[(LONG)PLANES*16000+128]; /* reserve screens */
WORD myRandom(WORD max)
{static LONG Seed = 0;
if (max == 0) return 0;
Seed = (5*Seed + 37);
return ((WORD)Seed % max);
}
WORD Laplace(char *Pic)
/* This routine returns 2^FIXEDNUM times the pixel value,
* Beta is fixed point (x.4 bits)
* The formular is :
* (2^FIXEDNUM)*lp
* = (2^FIXEDNUM) * P(0,0)
* + ( (2^FIXEDNUM)*BETA/4 ) ; this is the 'Beta' you can set.
* * ( 4*P(0,0) - P(-1,0)-P(1,0)-P(0,1)-P(0,-1) )
*/
{
return
((ERRTYP)*Pic<<FIXEDNUM)
+ Beta*
( (ERRTYP)
(*Pic<<2) - *(Pic-1) - *(Pic+1) - *(Pic+Width) - *(Pic-Width) );
}
int GenConvPixel(char *pic, WORD x, WORD y)
/* This rutine converts a point in the 'real' image to
* a point in the screen image. The procedure uses error-
* diffusion to determine the state of the new pixel.
* The Error filter is that of Floyd & Steinberg :
* / 1 5 3 \ /
* \ 7 X / / 16
* This rutine uses a table of levels to make the convertion
*/
{WORD i, level;
ERRTYP q, p, err, diffr, *P_levels;
if (x == 0 || x == Width-1)
p = (ERRTYP)*pic<<FIXEDNUM;
else
{ p = 7*Error1[x-1] + Error2[x-1] + 5*Error2[x] + 3*Error2[x+1];
if (y == 0 || y == Height-1 || Beta == 0)
p += (ERRTYP)*pic<<FIXEDNUM;
else
p += Laplace(pic);
}
/* add dynamic noise, set the initial difference to infinite */
diffr = MAXGRAY<<2;
q = p + (ERRTYP)myRandom(MaxRandom);
P_levels = &Levels[0];
/* find the level that introduces least error */
for(i = 0; i < n_levels; i++)
{ err = q - *P_levels++;
if (err < 0)
err = -err;
if (err < diffr)
{ diffr = err;
level = i;
}
}
/* Now, calculate the error made by quantisation (without noise) */
Error1[x] = (p - Levels[level]) >> 4;
return level;
}
void ClearError(void)
{int i;
Error1 = Error1Array;
Error2 = Error2Array;
for(i = 0; i < ERRWIDTH; i++)
Error1Array[i] = Error2Array[i] = 0;
}
void NextError(void)
{ERRTYP *tmp;
tmp = Error1; Error1 = Error2; Error2 = tmp;
}
void Convert2Gray(char *pic)
{LONG yoffset, wordpos;
WORD x, y, i, q, NextPix;
UWORD pix[PLANES], *screen[PLANES];
char *p, *oldphys;
Cconws("Converting picture to flicker...\r\n");
/* initialize screens */
oldphys = Physbase();
Setscreen((VOID *)-1, (Screens + 128L), -1);
screen[0] = Physbase();
for(i=1; i<PLANES; i++)
screen[i] = screen[i-1] + 16000L;
yoffset = 0;
Levels[1] = MAXGRAY/3; /* reinsert 2. element of array */
ClearError();
NextPix = 0;
for(y = 0; y < Height; y++)
{ p = pic + (LONG)y*Width;
wordpos = yoffset;
for(x = 0; x < Width; x++)
{ /* first clear first pixel in all planes */
for (i=0; i<PLANES; pix[i++] <<= 1);
q = GenConvPixel(p + (LONG)x, x, y);
while (q--) /* update all planes */
{ /* set the pixel in that plane */
pix[NextPix]++;
if (++NextPix >= PLANES) NextPix = 0;
}
/* When 16 pixels is made, then put them on the screen */
if ((x & 0xf) == 0xf)
{ for(i = 0; i<PLANES; i++)
*(screen[i] + wordpos) = pix[i];
wordpos++;
}
}
yoffset += WORDLINE;
NextError();
if (Bconstat(2)) break;
}
/* animate the screens */
do
{ for (i=0; i<PLANES; i++)
{ Vsync();
Setscreen((VOID *)-1,screen[i],-1);
}
} while (!Bconstat(2)); /* until a key have been pressed */
Setscreen((VOID *)-1,oldphys,-1);
}
void SimpleConvert2Gray(char *pic)
{LONG yoffset, wordpos;
WORD x, y;
UWORD pix, *screen, *oldphys;
char *p;
Cconws("Converting picture to mono...\r\n");
/* initialize screen */
oldphys = Physbase();
Setscreen((VOID *)-1, (Screens + 128L), -1);
screen = Physbase();
Levels[1] = MAXGRAY; /* reinsert 2. element of array */
ClearError();
yoffset = 0;
pix = 0;
for(y = 0; y < Height; y++)
{ p = pic + (LONG)y*Width;
wordpos = yoffset;
for(x = 0; x < Width; x++)
{ pix <<= 1;
if (GenConvPixel(p + (LONG)x, x, y))
pix++;
/* When 16 pixels is made, then put them on the screen */
if ((x & 0xf) == 0xf)
screen[wordpos++] = pix;
}
yoffset += WORDLINE;
NextError();
if (Bconstat(2)) break;
}
/* wait until a key have been pressed */
while (!Bconstat(2));
Setscreen((VOID *)-1,oldphys,-1);
}
int LoadPicture(const char *Name, char *Picture)
{int f;
Cconws("Loading picture\r\n");
if ( (f = Fopen(Name, 0) ) > 0)
{ Fseek(82l,f,0); /* ...skip TIFF header... */
Fread(f, (LONG)Width*Height, Picture);
Fclose(f);
return 0;
}
else
return 1;
}
/* 1 long resolution (0=low, 1=medium, 2=high)
* 16 words palette
* 23 longs reserved for expansion
* 16000 words picture data (screen memory)
*/
int LoadNEO(const char *Name, char *pic)
{int f,color,gray,i,j,pix;
WORD Palette[16];
UWORD Line[80], *LinePoint, plane1,plane2,plane3,plane4;
Cconws("Loading NEO-picture\r\n");
if ( (f = Fopen(Name, 0) ) > 0)
{ Fseek(4, f, 0);
Fread(f, 32, Palette);
/* convert all palette entrys to grayscale */
for (i=0; i<16; i++)
{ color = Palette[i];
gray = 26*((color ) & 7)
+ 151*((color >> 4) & 7)
+ 77*((color >> 8) & 7);
Palette[i] = 255 - gray/7;
}
Fseek(4*23, f, 1);
for(i=0; i<200; i++)
{ Fread(f, 160, Line);
LinePoint = Line;
for(j=0; j<320; j++)
{ if ((j & 15) == 0)
{ plane1 = *LinePoint++;
plane2 = *LinePoint++;
plane3 = *LinePoint++;
plane4 = *LinePoint++;
}
pix = 0;
if (plane1 & 0x8000) pix |= 1;
if (plane2 & 0x8000) pix |= 2;
if (plane3 & 0x8000) pix |= 4;
if (plane4 & 0x8000) pix |= 8;
gray = Palette[pix];
if (Zoom)
{ *(pic + (LONG)Width) = gray;
*pic++ = gray;
*(pic + (LONG)Width) = gray;
}
*pic++ = gray;
plane1 <<= 1; plane2 <<= 1;
plane3 <<= 1; plane4 <<= 1;
}
if (Zoom)
pic += (LONG)Width;
}
Fclose(f);
return 0;
}
else
return 1;
}
main(int argc, const char *argv[])
{char *ScreenBuf;
const char *p;
Beta = 2;
MaxRandom = 10;
Height = 400; Width = 575;
Flicker = 0; n_levels = 2;
while (--argc)
{ switch( *(p = *++argv) )
{ case 'W':
Width = atoi(p+1); break;
case 'H':
Height = atoi(p+1); break;
case 'R':
MaxRandom = atoi(p+1); break;
case 'L':
Beta = atoi(p+1); break;
case 'F':
Flicker = atoi(p+1);
if (Flicker)
n_levels = 4;
else
n_levels = 2;
break;
case 'N': /* Load 320x200 pics NEO */
Width = 320;
Height = 200;
Zoom = 0;
case 'Z': /* Load NEO and zoom to full screen */
if (*p == 'Z')
{ Width = 640;
Height = 400;
Zoom = 1;
}
if ((ScreenBuf = Malloc((LONG)Width*Height)) <= 0)
goto Error;
if (LoadNEO(p + 1, ScreenBuf))
goto Error1;
if (Flicker)
Convert2Gray(ScreenBuf);
else
SimpleConvert2Gray(ScreenBuf);
Mfree(ScreenBuf);
break;
case 'T': /* Load TIFF picture */
if ((ScreenBuf = Malloc((LONG)Width*Height)) <= 0)
goto Error;
if (LoadPicture(p + 1, ScreenBuf))
goto Error1;
if (Flicker)
Convert2Gray(ScreenBuf);
else
SimpleConvert2Gray(ScreenBuf);